#pragma once

#include <string>

static const wchar_t unicodeTag = 0xFEFF;

static DWORD CALLBACK LoadCallback( DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG* pcb ) 
{ 
    HANDLE hFile = (HANDLE)dwCookie; 
    ::ReadFile(hFile, pbBuff, cb, (DWORD*)pcb, NULL); 
    return 0; 
}

static DWORD CALLBACK SaveCallback( DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG* pcb ) 
{ 
    HANDLE hFile = (HANDLE) dwCookie; 
    ::WriteFile(hFile, pbBuff, cb, (DWORD*)pcb, NULL); 
    return 0;
}

template <class T> class RichInkPersist
{
public:

    RichInkPersist<T> ()
        : hReadFile(INVALID_HANDLE_VALUE) 
    {}

    bool Save(const std::wstring fileName, bool unicode)
    {
        HANDLE hWriteFile = ::CreateFile(fileName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
        if (hWriteFile == INVALID_HANDLE_VALUE)
            return false;

        if (unicode)
        {
            DWORD nWritten;
            ::WriteFile(hWriteFile, (LPVOID)&unicodeTag, sizeof(wchar_t), &nWritten, NULL);
        }

        EDITSTREAM   eds;
        eds.dwCookie = (DWORD) hWriteFile; 
        eds.dwError = 0; 
        eds.pfnCallback = SaveCallback;
        
        T* pT = static_cast<T*>(this);
        pT->StreamOut( unicode ? SF_UTEXT : SF_TEXT, eds );

        ::CloseHandle(hWriteFile);

        return true;
    }

    void Load(const std::wstring fileName, bool unicode)
    {
        if (hReadFile != INVALID_HANDLE_VALUE)
            ::CloseHandle(hReadFile);

        hReadFile = ::CreateFile(fileName.c_str(), GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0);
        if (unicode)
            ::SetFilePointer(hReadFile, sizeof(wchar_t), NULL, FILE_BEGIN);

        EDITSTREAM   eds;
        eds.dwCookie = (DWORD) hReadFile; 
        eds.dwError = 0; 
        eds.pfnCallback = LoadCallback;

        T* pT = static_cast<T*>(this);
        pT->StreamIn(unicode ? SF_UTEXT : SF_TEXT, eds);
    }

    virtual ~RichInkPersist()
    {
        if (hReadFile != INVALID_HANDLE_VALUE)
            ::CloseHandle(hReadFile);
    }

protected:

    HANDLE hReadFile;
};